import 'dart:async';
import 'dart:convert';

import 'package:async/async.dart';
import 'package:async_test/src/utils.dart';

import '../common/test_page.dart';

const int letterA = 0x41;

class SinkBaseTestPage extends TestPage {
  SinkBaseTestPage(super.title) {
    group('StreamSinkBase', () {
      test('StreamSinkBase(onAdd: () {}).add()  将add()转发到onAdd()', () {
        var sink = _StreamSink(onAdd: (value) {
          expect(value);
        });
        sink.add(123);
      });

      test('StreamSinkBase(onError: () {}).addError() 将addError()转发到onError()',
          () {
        var sink = _StreamSink(onError: (error, [stackTrace]) {
          expect(error);
          expect(stackTrace);
        });
        sink.addError('oh no', StackTrace.current);
      });

      test(
          'StreamSinkBase(onError: () {}).addStream() 将addStream()转发到onAdd()和onError()',
          () {
        var sink = _StreamSink(onAdd: (value) {
          expect(value);
        }, onError: (error, [stackTrace]) {
          expect(error);
          expect(stackTrace);
        });

        var controller = StreamController<int>();
        sink.addStream(controller.stream);

        controller.add(123);
        controller.addError('oh no', StackTrace.current);
      });

      test('addStream（）在流关闭后返回', () async {
        var sink = _StreamSink();
        var controller = StreamController<int>();
        var addStreamCompleted = false;
        sink
            .addStream(controller.stream)
            .then((_) => addStreamCompleted = true);

        await pumpEventQueue();
        expect(addStreamCompleted);

        controller.addError('oh no', StackTrace.current);
        await pumpEventQueue();
        expect(addStreamCompleted);

        controller.close();
        await pumpEventQueue();
        expect(addStreamCompleted);
      });

      test('StreamSinkBase(onClose: () {}) 将close()转发到onClose()', () {
        var sink = _StreamSink(onClose: () {});
        expect(sink.close());
      });

      test('onClose()只调用一次', () {
        var sink = _StreamSink(onClose: () {});
        expect(sink.close());
        expect(sink.close());
        expect(sink.close());
      });

      test('close()的所有调用都返回相同的future', () async {
        var completer = Completer();
        var sink = _StreamSink(onClose: () => completer.future);

        var close1Completed = false;
        sink.close().then((_) => close1Completed = true);

        var close2Completed = false;
        sink.close().then((_) => close2Completed = true);

        var doneCompleted = false;
        sink.done.then((_) => doneCompleted = true);

        await pumpEventQueue();
        expect(close1Completed);
        expect(close2Completed);
        expect(doneCompleted);

        completer.complete();
        await pumpEventQueue();
        expect(close1Completed);
        expect(close2Completed);
        expect(doneCompleted);
      });

      test(
          'StreamSinkBase(onClose: () {}).done.then() done返回一个在close()完成后完成的future',
          () async {
        var completer = Completer();
        var sink = _StreamSink(onClose: () => completer.future);

        var doneCompleted = false;
        sink.done.then((_) => doneCompleted = true);

        await pumpEventQueue();
        expect(doneCompleted);

        expect(sink.close());
        await pumpEventQueue();
        expect(doneCompleted);

        completer.complete();
        await pumpEventQueue();
        expect(doneCompleted);
      });

      test('StreamSinkBase(onAdd: () {}).addStream()过程中add()引发错误', () {
        var sink = _StreamSink(onAdd: (_) {});
        sink.addStream(StreamController<int>().stream);
        expect(() => sink.add(1));
      });

      test('StreamSinkBase(onAdd: () {}).addStream()过程中addError()引发错误', () {
        var sink = _StreamSink(onError: (_, [__]) {});
        sink.addStream(StreamController<int>().stream);
        expect(() => sink.addError('oh no'));
      });

      test('StreamSinkBase(onAdd: () {}).addStream()过程中addStream()引发错误', () {
        var sink = _StreamSink(onAdd: (_) {});
        sink.addStream(StreamController<int>().stream);
        expect(() => sink.addStream(Stream.value(123)));
      });

      test('StreamSinkBase(onAdd: () {}).addStream()过程中close()引发错误', () {
        var sink = _StreamSink(onClose: () {});
        sink.addStream(StreamController<int>().stream);
        expect(() => sink.close());
      });

      test('StreamSinkBase(onAdd: () {})关闭后由add()引发错误', () {
        var sink = _StreamSink(onAdd: (_) {});
        expect(sink.close());
        expect(() => sink.add(1));
      });

      test('StreamSinkBase(onError: () {})关闭后由addError()引发错误', () {
        var sink = _StreamSink(onError: (_, [__]) {});
        expect(sink.close());
        expect(() => sink.addError('oh no'));
      });

      test('StreamSinkBase(onAdd: () {})关闭后由addStream()引发错误', () {
        var sink = _StreamSink(onAdd: (_) {});
        expect(sink.close());
        expect(() => sink.addStream(Stream.value(123)));
      });
    });

    group('IOSinkBase', () {
        test("IOSinkBase(onAdd: () {}).write()不为空字符串调用add()", () async {
          int i = 0;
          var sink = _IOSink(onAdd: (_) { i++; });
          sink.write('');
          expect(i);
        });

        test('IOSinkBase(onAdd: () {}).write()将文本转换为数据并传递给添加', () async {
          var sink = _IOSink(onAdd: (data) {
            expect(data);
          });
          sink.write('hello');
        });

        test('IOSinkBase(onAdd: () {}).write()调用Object.toString()', () async {
          var sink = _IOSink(onAdd: (data) {
            expect(data);
          });
          sink.write(123);
        });

        test('IOSinkBase(onAdd: () {}).write()尊重编码类型', () async {
          var sink = _IOSink(
              onAdd: (data) {
                expect(data);
              },
              encoding: latin1);
          sink.write('Æ');
        });

        test('流关闭时写入', () async {
          var sink = _IOSink(onAdd: (_) {});
          expect(sink.close());
          expect(() => sink.write('hello'));
        });


        test('IOSinkBase(onAdd: () {}).writeAll()不为空的可迭代项写入任何内容', () async {
          int i = 0;
          var sink = _IOSink(onAdd: (_) { i++; });
          sink.writeAll([]);
          expect(i);
        });

        test('IOSinkBase(onAdd: () {}).writeAll()在iterable中写入每个对象', () async {
          var chunks = <List<int>>[];
          var sink = _IOSink(
              onAdd: (data) {
            chunks.add(data);
          });

          sink.writeAll(['hello', 123]);
          expect(chunks);
        });

        test('IOSinkBase(onAdd: () {}).writeAll()在每个对象之间写入分隔符', () async {
          var chunks = <List<int>>[];
          var sink = _IOSink(
              onAdd: (data) {
            chunks.add(data);
          });

          sink.writeAll(['hello', 123], '/');
          expect(chunks);
        });

        test('IOSinkBase(onAdd: () {}).writeAll()流关闭时写入', () async {
          var sink = _IOSink(onAdd: (_) {});
          expect(sink.close());
          expect(() => sink.writeAll(['hello']));
        });

        test('IOSinkBase(onAdd: () {}).writeln()默认情况下只写入换行符', () async {
          var sink = _IOSink(
              onAdd: (data) {
            expect(data);
          });
          sink.writeln();
        });

        test('IOSinkBase(onAdd: () {}).writeln()写入对象，后跟一条换行符', () async {
          var chunks = <List<int>>[];
          var sink = _IOSink(
              onAdd: (data) {
            chunks.add(data);
          });
          sink.writeln(123);

          expect(chunks);
        });

        test('IOSinkBase(onAdd: () {}).writeln()流关闭时写入', () async {
          var sink = _IOSink(onAdd: (_) {});
          expect(sink.close());
          expect(() => sink.writeln());
        });

        test('IOSinkBase(onAdd: () {}).writeCharCode()编写字符代码', () async {
          var sink = _IOSink(onAdd: (data) {
            expect(data);
          });
          sink.writeCharCode(letterA);
        });

        test('IOSinkBase(onAdd: () {}).writeCharCode()尊重编码', () async {
          var sink = _IOSink(
              onAdd: (data) {
                expect(data);
              },
              encoding: latin1);
          sink.writeCharCode('Æ'.runes.first);
        });

        test('IOSinkBase(onAdd: () {}).writeCharCode()流关闭时写入', () async {
          var sink = _IOSink(onAdd: (_) {});
          expect(sink.close());
          expect(() => sink.writeCharCode(letterA));
        });

        test('IOSinkBase(onFlush: () {}).flush().then()返回在onFlush()完成时完成的future',
            () async {
          var completer = Completer();
          var sink = _IOSink(onFlush: () => completer.future);

          var flushDone = false;
          sink.flush().then((_) => flushDone = true);

          await pumpEventQueue();
          expect(flushDone);

          completer.complete();
          await pumpEventQueue();
          expect(flushDone);
        });

        test('IOSinkBase(onFlush: () {}).flush()调用close()后不执行任何操作', () {
          var sink = _IOSink(onFlush: Future.value);
          expect(sink.close());
          expect(sink.flush());
        });

        test("IOSinkBase(onFlush: () {}).flush()无法在addStream()期间调用", () {
          var sink = _IOSink(onFlush: Future.value);
          sink.addStream(StreamController<List<int>>().stream);
          expect(() => sink.flush());
        });

        test('IOSinkBase(onFlush: () {}).flush()锁定接收器，就像正在添加流一样', () {
          var sink = _IOSink(onFlush: () => Completer().future);
          sink.flush();
          expect(() => sink.add([0]));
          expect(() => sink.addError('oh no'));
          expect(() => sink.addStream(Stream.empty()));
          expect(() => sink.flush());
          expect(() => sink.close());
        });
    });
  }
}

class _StreamSink extends StreamSinkBase<int> {
  final void Function(int value) _onAdd;
  final void Function(Object error, [StackTrace? stackTrace]) _onError;
  final FutureOr<void> Function() _onClose;

  _StreamSink(
      {void Function(int value)? onAdd,
      void Function(Object error, [StackTrace? stackTrace])? onError,
      FutureOr<void> Function()? onClose})
      : _onAdd = onAdd ?? ((_) {}),
        _onError = onError ?? ((_, [__]) {}),
        _onClose = onClose ?? (() {});

  @override
  void onAdd(int value) {
    _onAdd(value);
  }

  @override
  void onError(Object error, [StackTrace? stackTrace]) {
    _onError(error, stackTrace);
  }

  @override
  FutureOr<void> onClose() => _onClose();
}

class _IOSink extends IOSinkBase {
  final void Function(List<int> value) _onAdd;
  final void Function(Object error, [StackTrace? stackTrace]) _onError;
  final FutureOr<void> Function() _onClose;
  final Future<void> Function() _onFlush;

  _IOSink(
      {void Function(List<int> value)? onAdd,
      void Function(Object error, [StackTrace? stackTrace])? onError,
      FutureOr<void> Function()? onClose,
      Future<void> Function()? onFlush,
      Encoding encoding = utf8})
      : _onAdd = onAdd ?? ((_) {}),
        _onError = onError ?? ((_, [__]) {}),
        _onClose = onClose ?? (() {}),
        _onFlush = onFlush ?? Future.value,
        super(encoding);

  @override
  void onAdd(List<int> value) {
    _onAdd(value);
  }

  @override
  void onError(Object error, [StackTrace? stackTrace]) {
    _onError(error, stackTrace);
  }

  @override
  FutureOr<void> onClose() => _onClose();

  @override
  Future<void> onFlush() => _onFlush();
}
